'''
Created on Apr 20, 2012

@author: root
'''




from Base import Base
from FileOps import FileOps
from NodeInfo import NodeInfo
from User import User
#from XML_File import XML_File
import Queue
#import datetime
import getpass
import os
#import shutil
import threading
#import time


class SystemConfiguration(Base):
   
    Nodes = []
    Users = []
    baseDir = ""
    goldDir = ""
    prevDir = ""
    nodeInfo = object
    cmdQueue = Queue.Queue()
    isSudo = False
    fileops = None
    
    
    def CheckSudoSetup(self):
        
        ''' check commands that they can run and for tty '''
        print"    * Testing Root/Sudo User Access"
        self.LogInfo("Testing Root/Sudo User Access")
        threadCount = 0
        Threads = []
        rtnStatus = 0
        if str(self.installUser).upper() == "ROOT": 
            sudoCMD = "ls -l "
        else:
            sudoCMD = "sudo -l "
            self.installSudo = "sudo "
            self.isSudo = True

        for node in self.Nodes:
            Threads.append(threading.Thread(target=self.SSHExec,args=(sudoCMD,node.hostName,self.installUser,self.installPW)))
            Threads[threadCount].daemon=True
            Threads[threadCount].start()
            threadCount = threadCount + 1

        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
            if (status == 0):
                print"        * Root Privileges Granted for "+str(username) + " on " +str(hostName)
                self.LogInfo("Root Privileges Granted for "+str(username) + " on " +str(hostName))
                self.LogInfo(results)

            else:
                self.LogError("Problem with Root Privileges for "+ str(username) + " on " +  str(hostName))
                self.LogError(results)

                print "        * ERROR: Problem with Root Privileges for "+ str(username) + " on " +  str(hostName)
                rtnStatus =  -1
      
        if (rtnStatus == 0):
            self.LogInfo("Install User Login is Valid")
            return 0
        else:
            self.LogError("Invalid Install User Login")
            return -1 
            
            
   
            
    def SetInstallUser(self):
       
       
            os.system('clear')
            print "---------------------------------------------------"
            print "          PACHYDERM USER INFORMATION"
            print "---------------------------------------------------"
            self.installUser = raw_input('Enter Install User (root or a user with sudo privileges) : ')
            self.installPW = getpass.getpass("Enter Install User Password : ")
            print "---------------------------------------------------"
            print "        Running User Verification Tests"
            print "---------------------------------------------------"

            if (self.CheckSudoSetup() == 0):
        
                user = User(self.installUser,self.installPW,"i","i",self.isSudo)
                self.Users.append(user)
                return 0
            else:
                self.LogError("Errors seen using Install User")
                print "---------------------------------------------------"
                print "        Error  Testing Install User"
                print "---------------------------------------------------"

                return -1
            
   
                
#    def PrepareTmp(self,tmpDir):
#    
#        tmpStatus = 0
#        threadCount = 0
#        Threads = []
#        for node in self.Nodes:
#            
#            self.LogInfo("Creating Temporary Directories on Node: "+node.hostName)
#           
#            mkdirCMD = str(self.installSudo) + "/bin/mkdir -p "+ tmpDir
#            Threads.append(threading.Thread(target=self.SSHExec,args=(mkdirCMD,node.hostName,self.installUser,self.installPW)))
#            Threads[threadCount].daemon=True
#            Threads[threadCount].start()
#            threadCount = threadCount + 1
#        for thread in Threads:
#            thread.join()
#            (hostName,username,status,results) = self.returnQueue.get()
#            if (status == 0):
#                output = "Temporary Directories created on Node: "+hostName
#                self.LogInfo(output+" : "+str(results))
#                print "    * "+output
#            else:
#                self.LogError("Cannot create Temporary Directories on " + str(hostName)+" : "+str(results)+" ; Exiting")
#                print "    * ERROR Creating Temporary Directories on Node: "+hostName
#                tmpStatus = -1
#        if (tmpStatus == 0):
#            self.LogInfo("All Temporary Directories have been created correctly.")
#        else:
#            self.LogError("Temporary Directories were not created properly")
#            return -1 
    
    def SSHKeyShare(self):
        
        
        
        
        '''
        Method:  SSHKeyShare
        Purpose: Share Public Keys across cluster to allow Passwordless SSH Login.
                 It should maintain any previous relationships setup prior
                 
                 Need Passwordless SSH for mapred, hdfs, and the Install User.
        '''
        
        
        
        nodeKeyFiles = []
        knownHostsString = ""
        pwStatus = 0
        print "    * Configuring Passwordless SSH for all Hadoop Admin Users in the Cluster"

        ''' Create new authorize_keys files on each host.  Save old ones.  Eventually 
        They will be added back in
        '''
        
        if len(self.installSudo):
            self.LogInfo("Sudo Privileges Setting detected for " + str(self.installUser))
            status = self.CheckSudoSetup()
            if (status == 0):
                self.LogInfo("Sudo Privileges Configuration Valid for Entire Cluster")
            else:
                return -1
        threadCount = 0
        Threads = []
        
        for node in self.Nodes:
            for user in self.Users:
                if ("ROOT" not in str(user.username).upper()):
                    print "        * Configuring Passwordless SSH for "+user.username+" on "+node.hostName
    #                if ("ROOT" in str(user.username).upper()):
    #                    remotePath = "/"+ str(user.username) + "/.ssh"
    #                else:
                    remotePath = "/home/"+str(user.username) + "/.ssh"
                   # Check for .ssh
                    if os.path.exists(remotePath):
                        keyGenCMD = "rm -rf "+ remotePath + " ; ssh-keygen -t rsa -P '' -f " + remotePath + "/id_rsa  < <(echo 'y') ; cat " + remotePath + "/id_rsa.pub >> " + remotePath + "/authorized_keys."+node.hostName+"."+user.username
                         
                    else:
                        keyGenCMD = "ssh-keygen -t rsa -P '' -f " + remotePath + "/id_rsa  < <(echo 'y') ; cat " + remotePath + "/id_rsa.pub >> " + remotePath + "/authorized_keys."+node.hostName+"."+user.username
                    if node.hostName not in knownHostsString:
                        knownHostsString = knownHostsString + node.hostName + "," + node.ipAddress + " "
                    Threads.append(threading.Thread(target=self.SSHExec,args=(keyGenCMD,node.hostName,user.username,user.password)))
                    Threads[threadCount].daemon=True
                    Threads[threadCount].start()
                    threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()


            if (status == 0):
                self.LogInfo("Create Key:"+str(hostName)+":"+str(username)+":"+str(results))
            else:
                self.LogError("Problem generating SSH Keys on "+ str(hostName)+"; Exiting")
                pwStatus = -1
                
        if (pwStatus == 0):
            self.LogInfo("All SSH Keys have been created correctly.")
        else:
            self.LogError("Problem creating SSH Keys")
            return -1
    

        
        ''' Move Authorized Keys Files to Install Host '''
            
        '''
           used manual method to set remote name.... paramiko would not seem to 
           evaluate $HOME on a get/put.
         '''
            
        self.ClearReturnQueue()
        threadCount = 0
        Threads = []
        for node in self.Nodes:
            for user in self.Users:
                if ("ROOT" not in str(user.username).upper()):

                    remoteFile = "/home/"+user.username+"/.ssh/authorized_keys."+node.hostName+"."+user.username
                    localFile = "./conf/setup/ssh/authorized_keys."+node.hostName+"."+user.username
                    Threads.append(threading.Thread(target=self.SSHGet,args=(node.hostName,user.username,user.password,remoteFile,localFile)))
                    Threads[threadCount].daemon=True
                    Threads[threadCount].start()
                    threadCount = threadCount + 1
                    nodeKeyFiles.append(localFile)

        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()

            if (status == 0):
                self.LogInfo("Move Keys to Install Server:"+str(hostName)+":"+str(username)+":"+str(results))
            else:
                self.LogError("Problem Moving Keys from "+ str(hostName)+" to Install Server for user: "+str(username) +"; Exiting")
                pwStatus =  -1
                
        if (pwStatus == 0):
            self.LogInfo("All SSH Keys have been moved correctly.")
        else:
            self.LogError("Problem moving SSH Keys")
            return -1
        
        '''   Create Authorized Key File with ALL Hosts '''
        
        try:
            completeKeyFile = open("./conf/setup/ssh/authorized_keys", "w")
        except Exception, err:
            print err   
        for nodeKeyFile in nodeKeyFiles:
            try:
                nkFileHandle = open(nodeKeyFile, "r")
                completeKeyFile.write(nkFileHandle.read())
                self.LogInfo("Added "+str(nodeKeyFile).split('.')[2]+" keys to authorized_keys for "+str(nodeKeyFile).split('.')[3] + " on install servers")

            except Exception, err:
                pwStatus = -1
                self.LogError("Could not add "+ str(nodeKeyFile).split('.')[2]+" keys to authorized_keys for "+str(nodeKeyFile).split('.')[3] + " on install server; Exiting")
           
                        
        try:
            completeKeyFile.close()
            self.LogInfo("authorized_keys file for " + str(nodeKeyFile).split('.')[3] + " on install server complete")
        except:
            self.LogError("Could not write authorized_keys on install server for user: " + str(nodeKeyFile).split('.')[3] +"; Exiting")
            pwStatus -1
        
        if (pwStatus == 0):
            self.LogInfo("Authorized Keys File created correctly.")
        else:
            self.LogError("Problem creating Authorized Keys File")
            return -1    
        
        
        
#        ''' Push Authorized_keys file out to all Cluster Nodes '''
#        
#        remoteFile = "/home/"+user.username+"/.ssh/authorized_keys"
#        localFile = "./conf/setup/ssh/authorized_keys"
#        status = self.fileops.Push(self.Nodes,self.Users,localFile,remoteFile)

    
        self.ClearReturnQueue()

        threadCount = 0
        Threads = []
        for node in self.Nodes:
            for user in self.Users:
                if ("ROOT" not in str(user.username).upper()):

                    remoteFile = "/home/"+user.username+"/.ssh/authorized_keys"
                    localFile = "./conf/setup/ssh/authorized_keys"
                    Threads.append(threading.Thread(target=self.SSHPut,args=(node.hostName,user.username,user.password,localFile,remoteFile)))
                    Threads[threadCount].daemon=True
                    Threads[threadCount].start()
                    threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()

        if (status == 0):
            self.LogInfo("Moved authorized_keys for " + str(username) + " to " + str(hostName))
        else:
            self.LogError("Problem Moving authorized_keys for "+ str(username) +" from install host to "+ str(hostName)+"; Exiting")
            pwStatus -1
        if (pwStatus == 0):
            self.LogInfo("Authorized Keys File placed on Cluster Nodes.")
        else:
            self.LogError("Problem placing Authorized Keys Files on Cluster Nodes")
            return -1    
        
        ''' Create known_hosts files to avoid prompt when using ssh '''
        
        self.ClearReturnQueue()
        
        threadCount = 0
        Threads = []
        for node in self.Nodes:
            for user in self.Users:
                if ("ROOT" not in str(user.username).upper()):

                    knownHostsCMD = "ssh-keyscan -t rsa " + knownHostsString + " >> $HOME/.ssh/known_hosts"
                    Threads.append(threading.Thread(target=self.SSHExec,args=(knownHostsCMD,node.hostName,user.username,user.password)))
                    
                    Threads[threadCount].daemon=True
                    Threads[threadCount].start()
                    threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()

            if (status == 0):
                self.LogInfo("Created known_hosts file on "+str(hostName)+ "for "+str(username))
            else:
                self.LogError("Could not create known_hosts file on "+ str(hostName)+ " for " + str(username) +  "; Exiting")
                pwStatus =  -1
                
        if (pwStatus == 0):
            self.LogInfo("Known_hosts Files created correctly.")
        else:
            self.LogError("Problem creating known_hosts Files")
            return -1    
 
 
            '''
            chmod directories to the appropriate settings
            '''
            
      
        threadCount = 0
        Threads = []
        for node in self.Nodes:
            for user in self.Users:
                if ("ROOT" not in str(user.username).upper()):

                    chmodCMD = "chmod 600 $HOME/.ssh/authorized_keys ; chmod 700 $HOME/.ssh"
                    Threads.append(threading.Thread(target=self.SSHExec,args=(chmodCMD,node.hostName,user.username,user.password)))
                    Threads[threadCount].daemon=True
                    Threads[threadCount].start()
                    threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
            if (status == 0):
                self.LogInfo("Changed dir/file permission for $HOME/.ssh on "+str(hostName))
            else:
                self.LogError("Could not change dir/file permissions for $HOME/.ssh on "+ str(hostName)+  "; Exiting")
                return -1
        self.LogInfo("Passwordless SSH Correctly Configured for all Hadoop Admin Users")
        print "    * Passwordless SSH Configured for Cluster for all Hadoop Admin Users"
        return 0
    
    
    def ChkConfig(self,node,services,status):
        for service in services:

            chkCMD = str(self.installSudo) + "chkconfig hadoop-"+str(service)+" "+str(status)
            (execStatus,execReturn) =self.SSHExec(chkCMD,node.hostName,self.installUser,self.installPW,True)
            self.cmdQueue.put((node.hostName,chkCMD,execStatus,execReturn))
            
            # Disable bec
            if (execStatus == 0):
                print "        * hadoop-"+str(service) + " has been disabled on " + str(node.hostName)
                self.LogInfo("hadoop-"+str(service) + " has been disabled on " + str(node.hostName))
#            else:
#                print "        * ERROR: Failed to disable hadoop-"+str(service) + " on " + str(node.hostName)
#                self.LogError("Failed to disable hadoop-"+str(service) + " on " + str(node.hostName))

        
        
    
    def DisableInitD(self):
        threadCount = 0
        Threads = []
        disableStatus = 0
        self.LogInfo("Disabling Hadoop Init.d Scripts")
        print "    * Disabling Hadoop init.d Scripts"
        services =["namenode","datanode","jobtracker","tasktracker"]
        for node in self.Nodes:
            Threads.append(threading.Thread(target=self.ChkConfig,args=(node,services,"off")))
            Threads[threadCount].daemon=True
            Threads[threadCount].start()
            threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            
        while (not self.cmdQueue.empty()):
            (hostName,remotePkg,status,results) = self.cmdQueue.get()
            if (status == -1 ):
                disableStatus = -1
                
        if (disableStatus == 0):
            self.LogInfo("All Hadoop init.d Scripts Disabled")
            print "    * All Hadoop init.d Scripts Disabled"
        else:
            self.LogError("Failed to Disable all Hadoop init.d Scripts")
            print "    * Failed to Disable all Hadoop init.d Scripts"
        return disableStatus
    
   
    
    def SetUser(self,hadoopUser,type):
      
      
        pwStatus = 0
        threadCount = 0
        Threads = []
        user = "" 
        print "---------------------------------------------------"
        passWord = getpass.getpass("Enter a Password for the "+ str(hadoopUser) + " User: ")
        for node in self.Nodes:
            #passwordCMD = str(self.installSudo) + "useradd "+ str(hadoopUser) + ";" +str(self.installSudo) + "echo '"+ passWord + "' | "+ str(self.installSudo) +" /usr/bin/passwd "+ str(hadoopUser) + " --stdin"
            passwordCMD = str(self.installSudo) + "sh -c \"useradd "+ str(hadoopUser)+ "; echo '"+ passWord + "' | /usr/bin/passwd "+ str(hadoopUser) + " --stdin\""
            Threads.append(threading.Thread(target=self.SSHExec,args=(passwordCMD,node.hostName,self.installUser,self.installPW)))
            Threads[threadCount].daemon=True
            Threads[threadCount].start()
            threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
            user = ""
            if (status == 0):
                self.LogInfo("Password for  "+ str(hadoopUser)+ " changed on  "+str(hostName))
     
            else:
                self.LogError("Could not change password for " + str(hadoopUser) +  "; Exiting")
                pwStatus = -1
        
        if (pwStatus == 0):
            
            user = User(str(hadoopUser),passWord,type,str(hadoopUser),False)
            self.Users.append(user)
            
            # This will need to be taken care of to support Kerberos
#            if (str(hadoopUser)=="hadoop"):
#                user = User(str(hadoopUser),passWord,"m",str(hadoopUser),False)
#                self.Users.append(user)
                
                
                #ADD ERROR HANDLING
        return 0
    

    
   
        
    
      

    def __init__(self,Nodes,Users,baseDir):
        self.Users = Users
        self.Nodes = Nodes
        Base.__init__(self)
        Base.SetUsers(self,self.Users)
        
        self.baseDir = baseDir
        self.goldDir = self.baseDir + "/gold"
        self.previousDir = self.baseDir + "/previous"
        self.fileops = FileOps()
        

        self.nodeInfo = NodeInfo(self.Nodes,self.Users)
